Add PowerShell language model tools and redesign the Command Explorer#5508
Add PowerShell language model tools and redesign the Command Explorer#5508andyleejordan wants to merge 6 commits into
Conversation
Show Help previously printed `Get-Help` output into the integrated console and, when nothing was selected, sent the entire document as the help target. The latter was a `getWordRangeAtPosition` bug: off a word it returns `undefined`, and `doc.getText(undefined)` returns the whole document. Resolve the word at the cursor explicitly (falling back to the selection), send it to the new `powerShell/showHelp` request, and render the returned text in a read-only virtual document so help opens in a proper editor pane instead of an editable untitled buffer. Drafted by Copilot (Claude Opus 4.8). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The Command Explorer fetched the full command table up front (names, modules, and parameter metadata for everything), which took minutes to populate and showed a flat, hard-to-scan list. Rework it into a lazy, module-grouped tree: - Top-level nodes are modules (with version), expanded on demand; their commands are fetched per module with `excludeParameters` so only names and modules cross the wire. - Module-less commands are collected under a neutral "Functions & Scripts" node with a folder icon, and the request sets `excludeDefaultFunctions` so PowerShell's default-session plumbing doesn't clutter it. - Hovering a module shows its metadata via the new `powerShell/getModule` request, cached so repeated hovers don't re-fetch. - The inline Show Help / Insert command actions are gated to `viewItem == command` so they no longer appear on module nodes. Default the Command Explorer to visible. Because its default now equals the value the ISE profile sets, the ISE compatibility tests could no longer observe a revert by inequality; guard those assertions with `revertIsObservable`, which skips settings whose default already matches the ISE value. Drafted by Copilot (Claude Opus 4.8). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Register four read-only language model tools that Copilot can call when working with PowerShell, each backed by an existing PSES request so they report exactly what the user's session would: - `powershell_get_command` lists commands, optionally scoped by name and/or module, using the now-parameterized `powerShell/getCommand` request with `excludeParameters` so large listings stay cheap. - `powershell_get_help` returns `Get-Help` output via `powerShell/showHelp`. - `powershell_get_environment` reports the PowerShell version table. - `powershell_expand_alias` resolves aliases to their underlying commands. All four are read-only and declare no confirmation requirement. Contribute them in `package.json` and wire up `LanguageModelToolsFeature` in `extension.ts`. Drafted by Copilot (Claude Opus 4.8). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Record that `modules/` is a symlink to the sibling PowerShellEditorServices `module` directory, so building PSES deploys its DLLs straight into the path the extension and its tests load from — meaning C# changes require rebuilding PSES by hand, and `npm test` exercises the real Extension Host against the locally built server. This trips up anyone (including Copilot) who edits PSES and wonders why the extension didn't pick it up. Drafted by Copilot (Claude Opus 4.8). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Point the `PowerShellEditorServices` checkout at the coupled PR branch `andyleejordan/lm-tools-command-explorer` so #5508's new language model tool tests run against the server contract they depend on (name/module filtering on `getCommand`, `showHelp` returning `helpText`). Must be reverted before merge — once PSES #2298 lands on `main`, the default checkout passes. Drafted by Copilot (Claude Opus 4.8). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
This commit must be reverted before merge — once #2298 is on PSES Drafted by Copilot (Claude Opus 4.8). |
`@vscode/test-cli` defaults `--user-data-dir` to `.vscode-test/user-data` inside the workspace. On CI the workspace is nested three deep (`.../vscode-powershell/vscode-powershell/vscode-powershell/`), so the VS Code instance's IPC socket (`<user-data-dir>/<version>-main.sock`) exceeds macOS's 104-char `AF_UNIX` limit and the editor dies at startup with `listen EINVAL`, flaking the whole matrix (and cancelling the other OSes via fail-fast). Anchor `--user-data-dir` in `os.tmpdir()` so the socket path stays short on every platform. Drafted by Copilot (Claude Opus 4.8). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR extends the PowerShell VS Code extension by adding Language Model (LM) tools backed by existing PSES requests, redesigning the Command Explorer for module-oriented lazy loading, and updating Show Help to render as a read-only virtual document.
Changes:
- Added four read-only PowerShell LM tools (
powershell_get_command,powershell_get_help,powershell_get_environment,powershell_expand_alias) and integration tests. - Redesigned Command Explorer to group by module (including version), lazy-load tooltips, and avoid expensive parameter metadata transfer.
- Updated Show Help to fetch
Get-Helpoutput via an LSP request and render it in a read-only editor pane; updated Copilot cross-repo dev/test documentation and test harness configuration.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| test/features/LanguageModelTools.test.ts | Adds integration tests validating LM tool registration and basic behavior. |
| test/features/ISECompatibility.test.ts | Skips revert assertions for settings whose defaults equal their ISE values (to keep tests meaningful after default changes). |
| src/features/ShowHelp.ts | Switches Show Help to an LSP request and serves help output via a virtual read-only document. |
| src/features/LanguageModelTools.ts | Implements and registers the new PowerShell LM tools. |
| src/features/GetCommands.ts | Redesigns Command Explorer tree to module→command grouping, adds tooltip requests, and adds new request flags. |
| src/extension.ts | Wires up the LanguageModelTools feature during activation. |
| package.json | Contributes LM tools, gates Command Explorer inline actions to command nodes, and defaults Command Explorer visibility to true. |
| .vscode-test.mjs | Adjusts VS Code test launch args to shorten IPC socket path via --user-data-dir. |
| .github/workflows/ci-test.yml | Temporarily pins PSES checkout ref for coupled PR testing. |
| .github/copilot-instructions.md | Documents the cross-repo PSES + extension dev/test cycle for Copilot contributors. |
| private didChangeTreeData: vscode.EventEmitter< | ||
| CommandExplorerNode | undefined | ||
| > = new vscode.EventEmitter<CommandExplorerNode>(); |
| // Tooltips are cached by key (command name / module+version) so they survive | ||
| // tree rebuilds and repeat hovers don't re-issue the (slow) request. | ||
| private readonly commandTooltips = new Map<string, vscode.MarkdownString>(); |
| public async provideTextDocumentContent(uri: vscode.Uri): Promise<string> { | ||
| const commandName = uri.path; | ||
| const client = await LanguageClientConsumer.getLanguageClient(); | ||
| const result = await client.sendRequest(ShowHelpRequestType, { | ||
| text: commandName, | ||
| }); | ||
| return result.helpText || `No help found for '${commandName}'.`; |
| // workspace path, and its IPC socket blows past macOS's 104-char | ||
| // unix-socket limit, causing a flaky `listen EINVAL`. Anchor it in the | ||
| // OS temp dir so the socket path stays short on every platform. | ||
| "--user-data-dir", | ||
| join(tmpdir(), "vscode-powershell-test"), |
| repository: PowerShell/PowerShellEditorServices | ||
| # TEMPORARY: test against the coupled PSES PR #2298 until it merges. | ||
| # Revert this `ref` before merging (see PR #5508). | ||
| ref: andyleejordan/lm-tools-command-explorer | ||
| path: PowerShellEditorServices |
| public async invoke( | ||
| options: vscode.LanguageModelToolInvocationOptions<IGetCommandInput>, | ||
| _token: vscode.CancellationToken, | ||
| ): Promise<vscode.LanguageModelToolResult> { | ||
| const name = options.input.name?.trim(); | ||
| const module = options.input.module?.trim(); | ||
|
|
||
| if (!name && !module) { | ||
| return toToolResult( | ||
| "Provide a 'name' and/or 'module' filter to look up PowerShell commands.", | ||
| ); | ||
| } | ||
|
|
||
| // Get-Command -Name matches literally, so wrap bare text in wildcards to | ||
| // get intuitive "contains" matching while leaving explicit wildcards | ||
| // (and module names) untouched. | ||
| const namePattern = name && !/[*?[\]]/.test(name) ? `*${name}*` : name; | ||
|
|
||
| const client = await LanguageClientConsumer.getLanguageClient(); | ||
| const matches = await client.sendRequest(GetCommandRequestType, { | ||
| name: namePattern, | ||
| module, | ||
| }); |
| public async invoke( | ||
| options: vscode.LanguageModelToolInvocationOptions<IGetHelpInput>, | ||
| _token: vscode.CancellationToken, | ||
| ): Promise<vscode.LanguageModelToolResult> { | ||
| const client = await LanguageClientConsumer.getLanguageClient(); | ||
| const result = await client.sendRequest(ShowHelpRequestType, { | ||
| text: options.input.command, | ||
| }); | ||
| return toToolResult( | ||
| result.helpText || `No help found for '${options.input.command}'.`, | ||
| ); | ||
| } |
| public async invoke( | ||
| _options: vscode.LanguageModelToolInvocationOptions<EmptyInput>, | ||
| _token: vscode.CancellationToken, | ||
| ): Promise<vscode.LanguageModelToolResult> { | ||
| const client = await LanguageClientConsumer.getLanguageClient(); | ||
| const version = await client.sendRequest(PowerShellVersionRequestType); | ||
| const output = [ |
| public async invoke( | ||
| options: vscode.LanguageModelToolInvocationOptions<IExpandAliasInput>, | ||
| _token: vscode.CancellationToken, | ||
| ): Promise<vscode.LanguageModelToolResult> { | ||
| const client = await LanguageClientConsumer.getLanguageClient(); | ||
| const result = await client.sendRequest(ExpandAliasRequestType, { | ||
| text: options.input.text, | ||
| }); | ||
| return toToolResult(result.text); | ||
| } |
Adds PowerShell language model tools, redesigns the Command Explorer, and renders Show Help in a read-only editor pane. Backed by new LSP requests in PowerShell/PowerShellEditorServices#2298 — that PR must land with this one.
powerShell/showHelpand show it in a virtual document; fix the off-wordgetWordRangeAtPositionbug where an empty selection sent the whole document.getModulehover tooltips (cached), a neutral "Functions & Scripts" bucket with a folder icon,excludeParameters/excludeDefaultFunctionsrequest flags, inline-action gating toviewItem == command, and defaulting the view to visible (with arevertIsObservableguard so the ISE compatibility tests still pass).powershell_get_command,powershell_get_help,powershell_get_environment,powershell_expand_alias), each backed by an existing PSES request, contributed inpackage.jsonand wired up inextension.ts.Drafted by Copilot (Claude Opus 4.8)